#!/usr/bin/python
# -*- coding: utf-8 -*-


# cmap2owl -- Helper application to convert from concept maps to OWL ontologies
# Copyright (c) 2008-2013  Rodrigo Rizzi Starr
#  
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#  
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#  
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.


'''
This class edits a lexicon

@author: Rodrigo Rizzi Starr
@copyright: Copyright © 2008-2013 Rodrigo Rizzi Starr
@license: MIT License
@contact: rodrigo.starr@gmail.com
'''


import sys

# GTK+ imports
import pygtk
if not sys.platform == 'win32':
    pygtk.require('2.0')
try:
    import gtk
    import gtk.glade
except:
    sys.exit(1)
    
# Project imports
from classifiers import Classifiers
from log import log
log.debug("Loaded...")


class LexiconEditor:
    """Creates a new interface"""
    
    def __init__(self, filename):
        "Creates the widgets, but do not show them yet."
        
        self.filename = filename
        
        # Configures the interface
        self.buttonBar = self.createButtonBar()
        self.table = self.createTable()
        
        self.datastore = self.createTable()
        
        self.lexiconView = LexiconView(self.datastore)
        
        self.box = self.createBox()
        self.window = self.createWindow()

        
    
    def start(self):
        "Starts the editor"
        log.debug('Editing lexicon: ' + self.filename)
        self.window.show_all()
        gtk.main()
    
    def createWindow(self):
        "Returns a new window"
        
        window = gtk.Window(gtk.WINDOW_TOPLEVEL)
#        window.set_transient_for(parent)
        window.set_destroy_with_parent(True)
        window.set_modal(True)
        window.set_position(gtk.WIN_POS_CENTER)
        
        window.add(self.box)
        
        return window
    
    def createTable(self):
        "Returns a new table"
        
        # Load the classifiers (the lexicon)
        classifiers = Classifiers(filename = self.filename)
        classifiers.load()
        
        datastore = LexiconStore(classifiers)
        datastore.fill()
        
        return datastore
        
    def createButtonBar(self):
        "Returns a new button bar"
        buttonBar = gtk.HButtonBox()
        buttonBar.set_layout(gtk.BUTTONBOX_START)
        
        ok = gtk.Button(label='', stock = gtk.STOCK_OK)
        ok.connect('clicked', self.doOk)
        
        cancel = gtk.Button(label='', stock = gtk.STOCK_CANCEL)
        cancel.connect('clicked', self.doCancel)
        
        add = gtk.Button(label='', stock = gtk.STOCK_ADD)
        add.connect('clicked', self.doAdd)
        
        remove = gtk.Button(label='', stock = gtk.STOCK_REMOVE)
        remove.connect('clicked', self.doRemove)
        
        buttonBar.pack_start(add)
        buttonBar.pack_start(remove)
        
        buttonBar.pack_start(gtk.HBox(), expand=True)
        
        buttonBar.pack_start(ok)
        buttonBar.pack_start(cancel)
        
        return buttonBar
        
    def createBox(self):
        "Returns a new VBox"
        box = gtk.VBox()
        
        sw = gtk.ScrolledWindow()
        sw.add(self.lexiconView)
        box.pack_start(sw)
        box.pack_start(self.buttonBar, expand = False)
        
        return box
    
    def doOk(self, widget = None):
        "Called when the ok button is clicked"
        
        # Save and exit
        self.datastore.updateClassifiers()
        
        self.doCancel()
        
    def doCancel(self, widget = None):
        "Called when the cancel button is clicked"
        self.window.destroy()
        gtk.main_quit(widget)
        
    def doAdd(self, widget = None):
        "Called when the add button is clicked"
        
        cursor = self.lexiconView.get_cursor()[0]
        if cursor == None: # Nothing selected
            return
        
        it = self.datastore.get_iter(cursor)
        parent = self.datastore.iter_parent(it)
        if parent == None:
            sibling = None
            parent = it
        else:
            sibling = it
        
        newIter = self.datastore.insert_after(parent, sibling, row=('',))
        path = self.datastore.get_path(newIter)
        
        self.lexiconView.expand_to_path(path)
        self.lexiconView.set_cursor(path, self.lexiconView.col0, True)
        self.lexiconView.grab_focus()
        
        
    def doRemove(self, widget = None):
        "Called when the remove button is clicked"
        cursor = self.lexiconView.get_cursor()[0]
        if cursor == None: # Nothing selected
            return
        
        it = self.datastore.get_iter(cursor)
        parent = self.datastore.iter_parent(it)
        
        if parent != None:
            self.datastore.remove(it)
        
        
        
class LexiconStore(gtk.TreeStore):
    """A model for our tree"""
    
    def __init__(self, classifiers):
        log.debug("Initializing LexiconStoreStore")
        gtk.TreeStore.__init__(self, str)
        
        self.classifiers = classifiers
        self.model = classifiers.classifiers
        
    def fill(self):
        "Fill up the table with the data"
        
        for key, values in self.model.iteritems():
            parentHandle = self.append(None, (key,))
            for value in sorted(values):
                if isinstance(value, str):
                    value = unicode(value)
                self.append(parentHandle, (value,))

    def change(self, path, newValue):
        "Changes a value in the model"
        self[path][0] = newValue
        
    def updateClassifiers(self):
        "Update the values in the classifier instance to reflect the model"
        it = self.get_iter_root()
        
        while it != None:
            currentClass = self.get(it, 0)[0]
            
            children = set()
            if self.iter_has_child(it):
                childIt = self.iter_children(it)
                while childIt != None:
                    children.add(unicode(self.get(childIt, 0)[0]))
                    childIt = self.iter_next(childIt)
                    
            self.model[currentClass] = children
                
            it = self.iter_next(it)
        
        self.classifiers._realSave()    
        

class LexiconView(gtk.TreeView):
    """A tree specialized for showing lexicons"""
    
    def __init__(self, model):
        gtk.TreeView.__init__(self, model)
        
        # Request some size for us
        self. set_size_request(400, 500)
        
        self.set_headers_visible(True)
        
        self.set_property("show-expanders", True)
        
        self.rend_desc = gtk.CellRendererText()
        self.rend_desc.set_property("editable", True)
        self.rend_desc.connect("edited", self.cb_desc_edited, model)
        
        self.col0 = gtk.TreeViewColumn("Words", self.rend_desc, text = 0)
        self.col0.set_expand(True)
        self.col0.set_cell_data_func(self.rend_desc, self.isEditable)
        self.append_column(self.col0)
    
    def isEditable(self, column, cell_renderer, tree_model, iterable):
        "Configures the cell renderer"
        
        if tree_model.iter_parent(iterable) == None:
            cell_renderer.set_property("editable", False)
        else:
            cell_renderer.set_property("editable", True)
            
            
    def cb_desc_edited(self, caller, path, new_text, model):
        "Changes the model content"
        
        model.change(path, new_text)
        log.debug("Desc %s changed to %s" % (path, new_text))
    
if __name__ == "__main__":
    
    fOpen = 'classifiers.pickle'
    
    application = LexiconEditor(fOpen)
    application.start()
        
